﻿////****************************************************************************
////
//// Descriptive Name = A  data access wrapper library for 
//// IBM.Data.DB2.iSeries provider.
//// Short Name = ISeriesDataProxy
//// Function = A data access proxy for client applications. 
////
//// Copyright for IBM.Data.DB2.iSeries and other IBM libraries used 
//// belongs to IBM Corp 2008
////
////****************************************************************************
////============================================================================
//// Copyright © Shibu Raj - shibu.raj@gmail.com.  All Rights Reserved.
//// This code released under the terms of the 
//// GNU General Public License version 2 (GPLv2) 
//// (http://isereisdataproxy.codeplex.com/license)
////============================================================================

namespace ISeriesDataProxy
{
    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Transactions;
    using IBM.Data.DB2.iSeries;

    /// <summary>
    /// Class to enlist the connections involed in a particular transaction.
    /// </summary>
    internal static class TransactionScopeConnections
    {
        /// <summary>
        /// Dictionary object to hold all the enlisted transactions.
        /// </summary>
        private static Dictionary<Transaction, Dictionary<string, iDB2Connection>>
            transactionConnections = new Dictionary<Transaction, Dictionary<string, iDB2Connection>>();

        /// <summary>
        /// Retrieve the connection involved in a particular transaction.
        /// </summary>
        /// <param name="database">
        ///     Database object from which we need to retrieve the connection.
        /// </param>
        /// <returns>Connection involved in the transaction.</returns>
        public static iDB2Connection GetConnection(Db2Database database)
        {
            Dictionary<string, iDB2Connection> dictionary;
            iDB2Connection newOpenConnection;
            Transaction current = Transaction.Current;

            if (current == null)
            {
                return null;
            }

            transactionConnections.TryGetValue(current, out dictionary);
            if (dictionary != null)
            {
                dictionary.TryGetValue(database.ConnectionString, out newOpenConnection);
                if (newOpenConnection != null)
                {
                    return newOpenConnection;
                }
            }
            else
            {
                dictionary = new Dictionary<string, iDB2Connection>();
                lock (transactionConnections)
                {
                    transactionConnections.Add(current, dictionary);
                }
            }

            if (dictionary.ContainsKey(database.ConnectionString))
            {
                return dictionary[database.ConnectionString];
            }

            newOpenConnection = database.GetNewOpenConnection();
            current.TransactionCompleted +=
                new TransactionCompletedEventHandler(TransactionScopeConnections.OnTransactionCompleted);
            dictionary.Add(database.ConnectionString, newOpenConnection);
            return newOpenConnection;
        }

        /// <summary>
        /// Transaction completed event handler.
        /// </summary>
        /// <param name="sender">Object that triggers the event.</param>
        /// <param name="e">Transaction completed event arguments.</param>
        private static void OnTransactionCompleted(object sender, TransactionEventArgs e)
        {
            Dictionary<string, iDB2Connection> dictionary;
            transactionConnections.TryGetValue(e.Transaction, out dictionary);
            if (dictionary != null)
            {
                lock (transactionConnections)
                {
                    transactionConnections.Remove(e.Transaction);
                }

                foreach (iDB2Connection connection in dictionary.Values)
                {
                    if (connection != null)
                    {
                        if (connection.State == System.Data.ConnectionState.Open)
                        {
                            connection.Close();
                        }

                        connection.Dispose();
                        GC.SuppressFinalize(connection);
                    }
                }
            }
        }
    }
}